using System;
using LoggingMagic.AssemlyOperations;
using LoggingMagic.Injectors.Helpers;
using LoggingMagic.Injectors.Interfaces;
using LoggingMagic.LoggingParameters;
using Mono.Cecil;

namespace LoggingMagic.Injectors
{
    /// <summary>
    /// factory for instanciating necessary objects (plays a role of Dependency Container :))
    /// </summary>
    internal abstract class InjectorFactory : IInjectorFactory
    {
        protected readonly ModuleDefinition _module;
        protected readonly IAssemblyResolver _resolver;
        private readonly IMethodFinderParameters _parameters;

        protected InjectorFactory(ModuleDefinition module, IAssemblyResolver resolver, IMethodFinderParameters parameters)
        {
            _module = module;
            _resolver = resolver;
            _parameters = parameters;
        }

        private ProcessedLabel _processedLabel;
        public ProcessedLabel ProcessedLabel
        {
            get
            {
                if (_processedLabel == null)
                    _processedLabel = new ProcessedLabel(_module, _resolver);

                return _processedLabel;
            }
        }

        public virtual Processor Processor
        {
            get
            {
                return new Processor(ProcessedLabel,
                        new MethodFinder(_module, AttributesFinder, _parameters),
                        new MethodProcessor(_module, this)
                    );
            }
        }

        private AttributesFinder AttributesFinder
        {
            get
            {
                return new AttributesFinder(_resolver, _module);
            }
        }

        private MethodParametersToArray _methodParametersToArray;
        protected virtual MethodParametersToArray MethodParametersToArray
        {
            get
            {
                if (_methodParametersToArray == null)
                    _methodParametersToArray = new MethodParametersToArray(TypeReferencesProvider);
                return _methodParametersToArray;
            }
        }

        private TypeReferencesProvider _typeReferencesProvider;
        protected virtual TypeReferencesProvider TypeReferencesProvider
        {
            get
            {
                if (_typeReferencesProvider == null)
                {
                    _typeReferencesProvider = new TypeReferencesProvider(_module);
                }
                return _typeReferencesProvider;
            }
        }


        public abstract IInjector WithParameters { get; }
        public abstract IInjector WithoutParameters { get; }
    }
}